﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http.Controllers;
using System.Web.Http;
using System.Net.Http;
using System.Reflection;
namespace Xinchen.SOA.Server.ServiceHosting
{
    public class HttpActionSelector : IHttpActionSelector
    {
        public ILookup<string, HttpActionDescriptor> GetActionMapping(HttpControllerDescriptor controllerDescriptor)
        {
            var methods = controllerDescriptor.ControllerType.GetMethods();
            var result = new List<HttpActionDescriptor>();
            foreach (var method in methods)
            {
                var descriptor = new ReflectedHttpActionDescriptor(controllerDescriptor, method);
                result.Add(descriptor);
            }
            return result.ToLookup(x => x.ActionName);
        }

        public HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
        {
            var actionDescriptor = new ReflectedHttpActionDescriptor();
            var routeData = controllerContext.RouteData;
            object action = string.Empty;
            if (!routeData.Values.TryGetValue("action", out action))
            {
                throw new HttpResponseException(controllerContext.Request.CreateErrorResponse(System.Net.HttpStatusCode.NotFound, "在路由中未找到action"));
            }
            string actionName = action.ToString().ToLower();
            var methods = controllerContext.ControllerDescriptor.ControllerType.GetMethods().Where(x => x.Name.ToLower() == actionName);
            var count = methods.Count();
            MethodInfo method = null;
            switch (count)
            {
                case 0:
                    throw new HttpResponseException(controllerContext.Request.CreateErrorResponse(System.Net.HttpStatusCode.NotFound, "在控制器" + controllerContext.ControllerDescriptor.ControllerName + "中未找到名为" + actionName + "的方法"));
                case 1:
                    method = methods.FirstOrDefault();
                    break;
                default:
                    var httpMethod = controllerContext.Request.Method;
                    var filterdMethods = methods.Where(x =>
                        {
                            var verb = x.GetCustomAttribute<AcceptVerbsAttribute>();
                            if (verb == null)
                            {
                                throw new HttpResponseException(controllerContext.Request.CreateErrorResponse(System.Net.HttpStatusCode.NotFound, "在控制器" + controllerContext.ControllerDescriptor.ControllerName + "中找到多个名为" + actionName + "的方法，请考虑为这些方法加上AcceptVerbsAttribute特性"));
                            }
                            return verb.HttpMethods.Contains(httpMethod);
                        });
                    if (filterdMethods.Count() > 1)
                    {
                        throw new HttpResponseException(controllerContext.Request.CreateErrorResponse(System.Net.HttpStatusCode.NotFound, "在控制器" + controllerContext.ControllerDescriptor.ControllerName + "中找到多个名为" + actionName + "的方法，并且这些方法的AcceptVerbsAttribute都含有" + httpMethod.ToString() + "，发生重复"));
                    }
                    else if (filterdMethods.Count() <= 0)
                    {
                        throw new HttpResponseException(controllerContext.Request.CreateErrorResponse(System.Net.HttpStatusCode.NotFound, "在控制器" + controllerContext.ControllerDescriptor.ControllerName + "中找到多个名为" + actionName + "的方法，但没有方法被配置为可以响应" + httpMethod.ToString() + "请求"));
                    }
                    method = filterdMethods.FirstOrDefault();
                    break;
            }

            return new ReflectedHttpActionDescriptor(controllerContext.ControllerDescriptor, method);
        }
    }
}
